﻿using System;
using System.ComponentModel;
using System.Windows.Input;
using ClientOverflow.DataTransferObjects;
using ClientOverflow.ViewModels.Interfaces;
using DynamicControllersGeneration;

namespace ClientOverflow.ViewModels.Register
{
    /// <summary>
    /// UserRegistrationViewModel is a view-model that relies on a User as a model. The view-model is an abstract
    /// class which is implemented through the CreateUserRegistrationViewModel factory method. The actual
    /// instances are created using dynamic proxy. The proxy is in charge of routing the calls to the model, in
    /// addition it's in charge of implementation the errors validation in runtime.
    /// The view-model exposes in addition the Save command which performs the registration of the user.
    /// </summary>
    public abstract class UserRegistrationViewModel : IUserViewModel
    {
        private static readonly ViewModelGenerator viewModelsGenerator = new ViewModelGenerator();

        public static IUserViewModel CreateUserRegistrationViewModel(User user)
        {
            return viewModelsGenerator.Generate<UserRegistrationViewModel>(user);
        }

        protected UserRegistrationViewModel(User user)
        {
            this.user = user;
        }

        private const string MANDATORY_FIELD_ERROR_MESSAGE = "This field is mandatory";
        private const string PASSWORD_VERIFICATION_PROPERTY_NAME = "PasswordVerification";
        private const string DEPARTMENT_NAME_PROPERTY_NAME = "DepartmentName";

        private readonly User user;
        private ICommand save;

        public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { };

        [Validation(typeof (MandatoryValidator))]
        public abstract string Name { get; set; }

        [Validation(typeof(MandatoryValidator), typeof(EmailValidator))]
        public abstract string Email { get; set; }

        
        public string DepartmentName
        {
            get { return user.Department.Name; }
            set
            {
                user.Department.Name = value;
                PropertyChanged(this, new PropertyChangedEventArgs("DepartmentName"));
            }
        }

        [Validation(typeof(MandatoryValidator))]
        [RelatedProperty(PASSWORD_VERIFICATION_PROPERTY_NAME)]
        public abstract string Password { get; set; }

        private string passwordVerification;
        public string PasswordVerification
        {
            get { return passwordVerification; }
            set
            {
                passwordVerification = value;
            }
        }

        private string GetPasswordVerificationValidation()
        {
            if(string.IsNullOrEmpty(passwordVerification))
            {
                return MANDATORY_FIELD_ERROR_MESSAGE;
            }
            
            if (user.Password != passwordVerification)
            {
                return "Password and Verification must be same";
            }

            return null;
        }

        private string GetDepartmetnNameValidation()
        {
            if(string.IsNullOrEmpty(user.Department.Name))
            {
                return MANDATORY_FIELD_ERROR_MESSAGE;
            }
            
            return null;
        }

        public virtual string this[string columnName]
        {
            get
            {
                if (columnName == PASSWORD_VERIFICATION_PROPERTY_NAME)
                {
                    return GetPasswordVerificationValidation();
                }

                if (columnName == DEPARTMENT_NAME_PROPERTY_NAME)
                {
                    return GetDepartmetnNameValidation();
                }

                return null;
            }
        }

        public string Error { get { throw new NotImplementedException(); } }

        public ICommand Save
        {
            get
            {
                if (save == null)
                {
                    save = new SaveCommand(user);
                }

                return save;
            }
        }
    }
}